using System;
using System.Text;

namespace HTTPSrv
{
    public delegate bool HTTPOnPathExistCheck(string Path);
    public delegate byte[] HTTPOnRequest(string Path);
    public delegate byte[] HTTPOnRequestWithData(string Path, HTTPSinglePair[] Data);


    public class HTTPSrv
    {
        // initial declares
        System.Net.Sockets.TcpListener tLs;
        HTTPOneUseConnection[] hOuc;

        // Event hook thingies:
        public event HTTPOnPathExistCheck OnPathExistCheck;
        public event HTTPOnRequest OnRequest;
        public event HTTPOnRequestWithData OnRequestWithData;

        bool PathExistCheck(string Path)
        {
            if (OnPathExistCheck != null)
                return OnPathExistCheck(Path);
            else
                return true;
        }
        byte[] RequestPath(string Path)
        {
            if (OnRequest != null)
                return OnRequest(Path);
            else
                return System.Text.Encoding.ASCII.GetBytes("Hook 'OnRequest' in HTTPSrv not connected.  Reboot universe and try again\r\n");
        }
        byte[] RequestPathWithData(string Path, HTTPSinglePair[] Data)
        {
            if (OnRequestWithData != null)
                return OnRequestWithData(Path, Data);
            else
                return System.Text.Encoding.ASCII.GetBytes("Hook 'OnRequestWithData' in HTTPSrv not connected.  +++ OUT OF CHEESE ERROR +++\r\n");
        }




        /// <summary>
        /// Creates a new HTTPSrv object, and starts listening.
        /// </summary>
        /// <param name="ListenIP">IP address to listen for new connections on</param>
        /// <param name="ListenPort">Port number to listen for new connections on</param>
        public HTTPSrv(System.Net.IPAddress ListenIP, int ListenPort)
        {
            // Sigh.  Whatever.
            hOuc = new HTTPOneUseConnection[200];
            tLs = new System.Net.Sockets.TcpListener(ListenIP, ListenPort);

            //bool bOK = false;


            // Start listening.
            tLs.Start();
        }

        /// <summary>
        /// Destroys the HTTPSrv object, closing connections and stopping from listening beforehand.
        /// </summary>
        ~HTTPSrv()
        {
            // Nullify those bloody hooks...
            OnRequestWithData = null;
            OnRequest = null;
            OnPathExistCheck = null;


            // KILLKILLKILL
            for (int i = hOuc.GetLowerBound(0); i <= hOuc.GetUpperBound(0); i++)
                if (hOuc[i] != null)
                    if (hOuc[i].Active)
                        hOuc[i] = null;

            // Nowish would be nice.
            GC.Collect();

            // Stop listening...
            tLs.Stop();

            // .. And finish this thang off.
            tLs = null;
            hOuc = new HTTPOneUseConnection[0];
        }

        void AcceptNewConnection(int iArrayIndex)
        {
            hOuc[iArrayIndex] = new HTTPOneUseConnection(tLs.AcceptTcpClient());

            // Now hooks...
            hOuc[iArrayIndex].OnPathExistCheck += new HTTPOnPathExistCheck(PathExistCheck);
            hOuc[iArrayIndex].OnRequest += new HTTPOnRequest(RequestPath);
            hOuc[iArrayIndex].OnRequestWithData += new HTTPOnRequestWithData(RequestPathWithData);

            // Done!
        }

        public void Poll()
        {
            
            // Any new connections that need assigning..?
            if (tLs.Pending())
            {
                for (int i = 0; i <= hOuc.GetUpperBound(0); i++)
                {
                    if (hOuc[i] == null)
                    {
                        AcceptNewConnection(i);
                        break;
                    }
                }
            }

            // Poll all existing, current connections.
            for (int i = 0; i <= hOuc.GetUpperBound(0); i++)
            {
                if (hOuc[i] != null)
                {
                    if (hOuc[i].Active)
                    {
                        // Oh look, a live one.
                        hOuc[i].Poll();
                    }
                    else
                    {
                        // Oh look, another dead one..
                        hOuc[i] = null;
                    }
                }
            }
        }
    }
}
